package emby.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.Writer;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * EasyJava for file I/O
 *
 * NEEDS ZIP FILES
 *
 * @author Justin and <a href= "http://www.javapractices.com/topic/TopicAction.do?Id=42">this website</a>
 *
 */
public class IO {

	public static String file_sep = System.getProperty("file.separator");
	public static String file_sep_escaped = file_sep.equals("\\")? "\\\\" : file_sep;
	
	/**
	 * Splits a filename (ex. text.txt) into its name and extension (ex. "text" and ".txt")
	 * <BR>
	 * Returns null if a period is not present.
	 * @param s filename
	 * @return an array. 0th element is the filename, 1st  is the extension
	 */
	public static String[] splittext(String s){
		int indexOfPeriod = s.lastIndexOf('.');
		if(indexOfPeriod==-1) return null;
		String filename = s.substring(0,indexOfPeriod);
		String extension = s.substring(indexOfPeriod,s.length());
		String[] s1 = new String[2];
		s1[0]=filename;s1[1]=extension;
		return s1;
	}

	public static String getDirectory(String file){
		String slash = System.getProperty("file.separator");

		int indexOfSlash = file.lastIndexOf(slash);
		if(indexOfSlash==-1) return file;
		String filename = file.substring(0,indexOfSlash+1);
		return filename;
	}

	public static String getExtension(String file){
		int indexOfPeriod = file.lastIndexOf('.');
		if(indexOfPeriod==-1) return null;
		String extension = file.substring(indexOfPeriod,file.length());
		return extension;
	}
	public static String getFilename(String file){
		int indexOfPeriod = file.lastIndexOf('.');
		if(indexOfPeriod==-1) return file;
		String filename = file.substring(0,indexOfPeriod);
		return filename;
	}

	/**
	 * @param directory
	 * @param file
	 * @return
	 */
	public static String pathjoin(String directory, String file){
		return addSlashIfNecessary(directory)+ file;
	}

	/**
	 * Will add a slash at the end of directories in order to join it with a filename
	 * @param directory
	 * @return
	 */
	public static String addSlashIfNecessary(String directory){
		if( directory.lastIndexOf(file_sep) == directory.length()-1)
			return directory;
		else
			return directory+file_sep;
	}


	/**
	 * Serializes the object , compresses it using gzip, and stores the file at "filename"
	 * @param o
	 * @param filename where to write out the object
	 */
	public static void GZIPserialize(Serializable o, String filename){
		try {
			FileOutputStream fileoutput = new FileOutputStream(filename);
			ObjectOutputStream out = new ObjectOutputStream(new GZIPOutputStream(fileoutput));
			out.writeObject(o);
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Unzips a file, and returns the  object is represents
	 * @param t The type that the object should be. You can pass in any object of this type
	 * @param filename the filepath of the data
	 * @return
	 */
	public static <T> T GZIPdeserialize(T t, String filename){
		try {
			FileInputStream fileinput = new FileInputStream(filename);
			ObjectInputStream in = new ObjectInputStream(new GZIPInputStream(fileinput));
			T newobj = (T) in.readObject();
			in.close();
			return newobj;
		} catch (Exception e){
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Serializes the object and stores the file at "filename"
	 * @param o
	 * @param filename where to write out the object
	 */
	public static void serialize(Serializable o, String filename){
		try {
			FileOutputStream fileoutput = new FileOutputStream(filename);
			ObjectOutputStream out = new ObjectOutputStream(fileoutput);
			out.writeObject(o);
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	/**
	 * Returns the desialized object o.
	 * @param t The type that the object should be. You can pass in any object of this type
	 * @param filename the filepath of the data
	 * @return
	 */
	public static <T> T deserialize(T t, String filename){
		try {
			FileInputStream fileinput = new FileInputStream(filename);
			ObjectInputStream in = new ObjectInputStream(fileinput);
			T newobj = (T) in.readObject();
			in.close();
			return newobj;
		} catch (FileNotFoundException e){
			e.printStackTrace();
			return null;
		}catch (IOException e){
			return GZIPdeserialize(t, filename);
		}catch (ClassNotFoundException e){
			e.printStackTrace();
			return null;
		}

	}
	/**
	 * Returns the desialized object o.
	 * @param t The type that the object should be. You can pass in any object of this type
	 * @param filename the filepath of the data
	 * @return
	 * @throws FileNotFoundException
	 */
	public static <T> T deserializeErr(T t, String filename) throws FileNotFoundException{
		try {
			FileInputStream fileinput = new FileInputStream(filename);
			ObjectInputStream in = new ObjectInputStream(fileinput);
			T newobj = (T) in.readObject();
			in.close();
			return newobj;
		} catch (FileNotFoundException e){
			throw e;
		}catch (IOException e){
			return GZIPdeserialize(t, filename);
		}catch (ClassNotFoundException e){
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * Fetch the entire contents of a text file, and return it in a String.
	  * This style of implementation does not throw Exceptions to the caller.
	  * <a href= "http://www.javapractices.com/topic/TopicAction.do?Id=42">Code copied from here</a>
	 * @param filepath the filepath of the text file
	 * @return the text contained in the file
	 */
	public static String getText(String filepath){
		try {
			return getText(new File(filepath));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static String getTextErr(String filepath) throws FileNotFoundException{
		return getText(new File(filepath));
	}
	/**
	 * Fetch the entire contents of a text file, and return it in a String.
	  * This style of implementation does not throw Exceptions to the caller.
	  * <a href= "http://www.javapractices.com/topic/TopicAction.do?Id=42">Code copied from here</a>
	 * @param aFile the text file
	 * @return the text contained in the file
	 */
	public static String getText(File aFile) throws FileNotFoundException{
		 StringBuilder contents = new StringBuilder();
		    try {
		      //use buffering, reading one line at a time
		      //FileReader always assumes default encoding is OK!
		      BufferedReader input =  new BufferedReader(new FileReader(aFile));
		      try {
		        String line = null; //not declared within while loop
		        /*
		        * readLine is a bit quirky :
		        * it returns the content of a line MINUS the newline.
		        * it returns null only for the END of the stream.
		        * it returns an empty String if two newlines appear in a row.
		        */
		        while (( line = input.readLine()) != null){
		          contents.append(line);
		          contents.append(System.getProperty("line.separator"));
		        }
		      }
		      finally {
		        input.close();
		      }
		    }
		    catch (IOException ex){
		    	if(ex instanceof FileNotFoundException){
		    		throw (FileNotFoundException)ex;
		    	}
		      ex.printStackTrace();
		    }
		    return contents.toString();
	}

	/**
	 * Writes a string into a file, overwriting it in the process or creating a new file if it is nonexistant
	 * @param newText text to write
	 * @param filepath filepath of File to overwrite or create
	 */
	public static void write(String newText, String filepath)
	{
		write(newText, new File(filepath));
	}

	/**
	 * Writes a string into a file, asking to overwrite if there already exists a file there. (NOT WORKING YET)
	 * @param newText text to write
	 * @param filepath filepath of File to overwrite or create
	 */
	public static void safeWrite(String newText, String filepath)
	{
		safeWrite(newText, new File(filepath));
	}

	/**
	 * Writes a string into a file, overwriting it in the process or creating a new file if it is nonexistant
	 * <a href= "http://www.javapractices.com/topic/TopicAction.do?Id=42">Code copied from here</a>
	 * @param newText text to write
	 * @param originalFile file to write to
	 */
	public static void write(String newText, File originalFile)
	{
			try{
			setContents( originalFile , newText); }
			catch(FileNotFoundException a)
			{
				System.out.println("File not found, creating new file with that name");
				try {
					originalFile.createNewFile();
					write(newText, originalFile);
				} catch (IOException e) {
					System.err.println("IO Exception when trying to create new file");
					e.printStackTrace();
				}
			}
			 catch(IOException e)
			 {
				 System.err.println("IO exception (TextRWer: write)");
			 }
	 }

	/**
	 * Writes a string into a file, asking to overwrite if there already exists a file there. (NOT WORKING YET)
	 * <a href= "http://www.javapractices.com/topic/TopicAction.do?Id=42">Code copied from here</a>
	 * @param newText text to write
	 * @param originalFile file to write to
	 */
	public static void safeWrite(String newText, File originalFile)
	{
			try{
			setContents( originalFile , newText);
			String temp = getText(originalFile);
			int i = javax.swing.JOptionPane.showConfirmDialog(null,"A save with that name already exists. Overwrite?");
			if(i==1){ setContents(originalFile,temp);}

			}
			catch(FileNotFoundException a)
			{
				System.out.println("File not found, creating new file with that name");
				try {
					originalFile.createNewFile();
					write(newText, originalFile);
				} catch (IOException e) {
					System.err.println("IO Exception when trying to create new file");
					e.printStackTrace();
				}
			}
			 catch(IOException e)
			 {
				 System.err.println("IO exception (TextRWer: write)");
			 }
	 }

	  /**
	  * Change the contents of text file in its entirety, overwriting any
	  * existing text.
	  *<BR>
	  * This style of implementation throws all exceptions to the caller.
	  * <BR>
	  *<a href= "http://www.javapractices.com/topic/TopicAction.do?Id=42">Code copied from here</a>
	  * @param aFile is an existing file which can be written to.
	  * @throws IllegalArgumentException if param does not comply.
	  * @throws FileNotFoundException if the file does not exist.
	  * @throws IOException if problem encountered during write.
	  */
	  private static final void setContents(File aFile, String aContents)
	                                 throws FileNotFoundException, IOException {
	    if (aFile == null) {
	      throw new IllegalArgumentException("File should not be null.");
	    }
	    if (!aFile.exists()) {
	      throw new FileNotFoundException ("File does not exist: " + aFile);
	    }
	    if (!aFile.isFile()) {
	      throw new IllegalArgumentException("Should not be a directory: " + aFile);
	    }
	    if (!aFile.canWrite()) {
	      throw new IllegalArgumentException("File cannot be written: " + aFile);
	    }

	    //use buffering
	    Writer output = new BufferedWriter(new FileWriter(aFile));
	    try {
	      //FileWriter always assumes default encoding is OK!
	      output.write( aContents );
	    }
	    finally {
	      output.close();
	    }
	  }



}
